/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_log.h"

static 	int 	_gTraceLvl_Log = TRACELVL_NORMAL;

/* =====================================================================
** Log Interface Pool:
** We Need to Buffer Pool for Service each Ascii & Binary Log request.
** The Element of Pool is Fix size :
** Ascii  	: _S_LOG_ELEM_MAXSZ
** Binary	: _S_LOG_ELEM_MAXSZ
*/
#define _S_LOG_MAX_DESC 	  	0X40
#define _S_LOG_MAX_SFUNC 	  	0X20
#define _S_LOG_MAX_FITEM 		10000

/* The Element  Limit */
#define _S_LOG_ELEM_MAXSZ 		0X20000
#define _S_LOG_ELEM_MAXCNT 		0X1000
#define _S_LOG_ELEM_THRS 		0X0F 	/* Each Threshold number of Ascii/Binary Log element will trigger 1 record operation */


/* Type define of the Log Element, It's the Header of the Log info. */
typedef struct _t_log_elem{
	_t_bnode      	node;

	unsigned char	type;
	/* Timing */
	_t_vfs_ti 		idx;

	/* Function & Line  */
	char 			sFunc[_S_LOG_MAX_SFUNC];
	int 			sLine;

	/* User Summit */
	int  			lDesc;
	int   			lData;
	char  			desc[_S_LOG_MAX_DESC];
	char  			data[0];
}_t_log_elem;



/* Add Support for Stat of the File */
#include <sys/stat.h>
#include <fcntl.h>
	
static	__inline	int 	_SLog_BkFileI(_t_log_ctrl* pCtrl,   const char * filePath)
{
	int 				fd, ret;
	struct stat 		fStat;
	char				fPath[S_APP_MAX_PATH];

	ret = -1;
	if(pCtrl){
		if(pCtrl->pFileI){
			fclose(pCtrl->pFileI);
			pCtrl->pFileI = NULL;
		}
		if((filePath) && (SYS_STRLEN(filePath) < (S_APP_MAX_PATH - 10))){
			SYS_SNPRINTF(pCtrl->filePath, (S_APP_MAX_PATH-1), "%s", filePath);
		}else{
			SYS_SNPRINTF(pCtrl->filePath, (S_APP_MAX_PATH-1), "/tmp/");
		}
		/* First Check if Has the Index File :
		** a+
		** Open for reading and appending (writing at end of file).
		** The file is created if it does not exist. 
		** The initial file position for reading is at the beginning of the file, 
		** but output is always appended to the end of the file.
		*/
		SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.idx", pCtrl->filePath);
		pCtrl->pFileI= fopen(fPath, "a+");
		if(pCtrl->pFileI){
			fclose(pCtrl->pFileI);
			
			pCtrl->iCount = 0;
			/* File Stat */
			fd = open(fPath, O_RDWR);
			ret = fstat(fd, &fStat);
			if(ret == 0){
				pCtrl->iCount = fStat.st_size / sizeof(_t_vfs_ti);
			}
			close(fd);

			/* ReOpen */
			fopen(fPath, "a+");
		}
	}
	
	return ret;
}

static	__inline	int 	_SLog_BkFileA(_t_log_ctrl* pCtrl)
{
	int 				ret;
	char				fPath[S_APP_MAX_PATH];

	ret = -1;
	if(pCtrl){
		if(pCtrl->pFileA){
			fclose(pCtrl->pFileA);
			pCtrl->pFileA = NULL;
		}
		SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.a", pCtrl->filePath);
		pCtrl->pFileA= fopen(fPath, "a+");
		ret = 0;
	}
	
	return ret;
}

static	__inline	int 	_SLog_BkFileB(_t_log_ctrl* pCtrl)
{
	int 				ret;
	char				fPath[S_APP_MAX_PATH];

	ret = -1;
	if(pCtrl){
		if(pCtrl->pFileB){
			fclose(pCtrl->pFileB);
			pCtrl->pFileB = NULL;
		}
		SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.b", pCtrl->filePath);
		pCtrl->pFileB= fopen(fPath, "a+");
		ret = 0;
	}
	
	return ret;
}


static	__inline	int 	_SLog_BkFileM(_t_log_ctrl* pCtrl)
{
	int 				fd, ret;
	_t_vfs_ti 			last;
	char				fPath[S_APP_MAX_PATH];

	ret = -1;
	if(pCtrl && pCtrl->pFileI){
		if(pCtrl->pFileM){
			fclose(pCtrl->pFileM);
			pCtrl->pFileM = NULL;
		}
		ret = pCtrl->iCount / _S_LOG_MAX_FITEM;
		SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.m.%04d", pCtrl->filePath, ret);
		pCtrl->pFileM= fopen(fPath, "a+");

		/* We should Check the CountI */
		if((pCtrl->pFileM)&& (pCtrl->iCount > 0)){
			/* Set the iFile */
			pCtrl->iFile = ret;

			/* Seek the Offset */
			fseek(pCtrl->pFileI, (pCtrl->iCount -1)*sizeof(_t_vfs_ti), SEEK_SET);
			fread(&last, sizeof(_t_vfs_ti), 1, pCtrl->pFileI);
			ret = last.i_off + last.i_len;
			if((pCtrl->iCount % _S_LOG_MAX_FITEM) != 0){
				fseek(pCtrl->pFileM, ret, SEEK_SET);
				SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileM (%d) Seek to Idx:%d Off:%d Last:(%d - %d)\n", 
							pCtrl->iFile, 
							pCtrl->iCount,
							ret, 
							last.i_off,
							last.i_len);

				/* Set the iOffset */
				pCtrl->iOffset = ret;

				/* Close & Truncate */
				fclose(pCtrl->pFileM);
				fd = open(fPath, O_RDWR);
				ftruncate(fd, ret);

				/* ReOpen */
				pCtrl->pFileM= fopen(fPath, "a+");

			}
			else{
				ret = 0;
				SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileM (%d) Seek to: 0\n", 
							pCtrl->iFile);
				/* Set the iOffset */
				pCtrl->iOffset = 0;
			}
			
		}
		ret = 0;
	}
	
	return ret;
}

/* =====================================================================
** Log Record Functions For:
** 
**	_S_LOG_BKEND_STD
**	_S_LOG_BKEND_FILE
**
**  	Support Type: _S_LOG_T_ASCII / _S_LOG_T_BINARY
*/

#define _S_LOG_ANCHOR_FREE(pCtrl, pAnchor) \
	do{\
		SYS_ENTER_CS(&(pCtrl->lock));\
		MPool_FreeNi(&(pCtrl->mPool), &(pAnchor->queue));\
		BLST_ADD2H(&(pCtrl->aFreeQ),  &(pAnchor->node));\
		SYS_LEAVE_CS(&(pCtrl->lock));\
	}while(0)

static 	__inline 	void 	_SLog_RecFileAscii(_t_log_ctrl * pCtrl, _t_log_elem * pElem)
{
	FILE 		* pFileA;
	_t_vfs_ti 	* pIdx;
	
	pFileA = pCtrl->pFileA;
	if(!pFileA){
		_SLog_BkFileA(pCtrl);
		pFileA = pCtrl->pFileA;
	}
	if(pFileA && pElem){
		pIdx = &(pElem->idx);
		fprintf(pFileA, "<%02d:%02d|%02d:%02d:%02d+%03d:%03d>[%-32s][%d]\n", 
			(pIdx->t_mon + 1), 	
			pIdx->t_mday, 
			pIdx->t_hour,	
			pIdx->t_min,	
			pIdx->t_sec,
			pIdx->t_msec,	
			pIdx->t_usec,
			pElem->sFunc,	pElem->sLine);
		
		fprintf(pFileA, "Desc:%s\n", 	(pElem->desc));
		fprintf(pFileA, "%s\n",			pElem->data);
		
		#if 1
		fflush(pFileA);
		#endif
	}
	
	return;
}

static 	__inline 	void 	_SLog_RecFileBinary(_t_log_ctrl * pCtrl, _t_log_elem * pElem)
{
	int 				j;
	unsigned char 	* 	pData;
	FILE 			* 	pFileB;
	_t_vfs_ti 		* 	pIdx;

	pFileB = pCtrl->pFileB;
	if(!pFileB){
		_SLog_BkFileB(pCtrl);
		pFileB = pCtrl->pFileB;
	}
	if(pFileB && pElem){
		pIdx = &(pElem->idx);
		fprintf(pFileB, "<%02d:%02d|%02d:%02d:%02d+%03d:%03d>[%-32s][%d]\n", 
			(pIdx->t_mon + 1), 			
			pIdx->t_mday,	
			pIdx->t_hour,	
			pIdx->t_min,	
			pIdx->t_sec,
			pIdx->t_msec,	
			pIdx->t_usec,
			pElem->sFunc,	pElem->sLine);
		
		fprintf(pFileB, "Desc:%s\n", 	(pElem->desc));
		for(j=0, pData = (unsigned char *)(pElem->data); j < pElem->lData; j++, pData++){
			if(j%32 == 0){
				fprintf(pFileB, "%04x: ", j);
			}
			else if(j%4 == 0){
				fprintf(pFileB, " - ");
			}
			fprintf(pFileB, "%02x", *pData);
			if(j%32 == 31){
				fprintf(pFileB, "\n");
			}
		}
		fprintf(pFileB, "\n");

		#if 1
		fflush(pFileB);
		#endif
	}
	return;
}

static 	__inline 	void 	_SLog_RecFileMon(_t_log_ctrl * pCtrl, _t_log_elem * pElem)
{
	int 				ret;
	FILE 			* 	pFileI;
	FILE 			* 	pFileM;

	pFileI = pCtrl->pFileI;
	if(!pFileI){
		_SLog_BkFileI(pCtrl, pCtrl->filePath);
		pFileI = pCtrl->pFileI;
	}
	pFileM = pCtrl->pFileM;
	if(!pFileM){
		_SLog_BkFileM(pCtrl);
		pFileM = pCtrl->pFileM;
	}
	
	if(pFileI && pElem && pFileM){
		pElem->idx.i_idx = (pCtrl->iCount % _S_LOG_MAX_FITEM);
		pElem->idx.i_off = pCtrl->iOffset;
		
		/* Check the File No */
		ret = (pCtrl->iCount) / _S_LOG_MAX_FITEM;
		if(ret != pCtrl->iFile){
			/* Close First */
			SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileM (%d) Close - (%d) Open\n", 
						pCtrl->iFile, ret);
			_SLog_BkFileM(pCtrl);
			pFileM = pCtrl->pFileM;
		}
		if(pFileM){
			/* Write Data File */
			fwrite(pElem->data, pElem->lData, 1, pFileM);
			/* Write Index File */
			fwrite(&(pElem->idx), sizeof(_t_vfs_ti), 1, pFileI);
			pCtrl->iCount 	 += 1;
			pCtrl->iOffset   += pElem->lData;
			#if 1
			fflush(pFileM);
			fflush(pFileI);
			#endif
		}
	}
	return;
}


int 	SLog_NetEnable(_t_log_ctrl * pCtrl)
{
	if(pCtrl && (pCtrl->bkEnd & _S_LOG_BKEND_NET)){
		pCtrl->bNet = 1;
		return 0;
	}
	return -1;
}

int 	SLog_NetDisable(_t_log_ctrl * pCtrl)
{
	if(pCtrl && (pCtrl->bkEnd & _S_LOG_BKEND_NET)){
		pCtrl->bNet = 0;
		return 0;
	}
	return -1;
}

int 	SLog_NetSetIPPort(_t_log_ctrl * pCtrl, unsigned int ip, unsigned short port)
{
	int ret;
	
	if(pCtrl){
		_IPPORT_GEN(&(pCtrl->ipPort), ip, port);
		if(pCtrl->sock != S_SOCKET_INVALID){
			close(pCtrl->sock);
			pCtrl->sock = S_SOCKET_INVALID;
		}
		pCtrl->sock = SockCreate_Udp(_F_NO, _S_LOG_SVR_PORT);
		S_SOCK_SET_NONBLOCK(pCtrl->sock, ret);
		S_SOCK_SET_NOCHKSUM(pCtrl->sock, ret);
		S_SOCK_SET_LOWDELAY(pCtrl->sock, ret);
		pCtrl->bkEnd |= _S_LOG_BKEND_NET;
		return 0;
	}

	return -1;
}

int 	SLog_NetTx(_t_log_ctrl * pCtrl, unsigned char * pData, int lData)
{
	int 				sock;
	_u_ipport		*	pIPPort;
	S_SOCKET_ADDRIN 	sockAddr;

	if(pCtrl){
		sock	= pCtrl->sock;
		pIPPort = &(pCtrl->ipPort);
		if(	(sock != S_SOCKET_INVALID) && 
			(_IPPORT_VALID(pIPPort))){
			S_ADDRIN_INIT(sockAddr, _IPPORT_IP(pIPPort), _IPPORT_PORT(pIPPort));
			return SockTx_Udp(sock, pData, lData, &sockAddr );
		}
	}
	return -1;
}


/* Change to the directory ARG. */
#define S_LOG_NET_TO 	2000

int 	SLog_NetRx(_t_log_ctrl * pCtrl, _t_cbentry * pCbEntry)
{
	int 				sock;

	if(pCtrl && pCbEntry){
		sock	= pCtrl->sock;
		if(	sock != S_SOCKET_INVALID){
			return SockRxSel_Udp(sock, pCbEntry, S_LOG_NET_TO );
		}
	}
	return -1;
}


static 	__inline 	void 	_SLog_RecNet(_t_log_ctrl * pCtrl, _t_log_elem * pElem)
{
	int 			  	sock;
	_u_ipport 		* 	pIPPort;
	S_SOCKET_ADDRIN 	sockAddr;

	sock	= pCtrl->sock;
	pIPPort = &(pCtrl->ipPort);
	if(	(pCtrl->bNet == 1) && 
		(sock != S_SOCKET_INVALID) && 
		(_IPPORT_VALID(pIPPort))){
		S_ADDRIN_INIT(sockAddr, _IPPORT_IP(pIPPort), _IPPORT_PORT(pIPPort));
		SockTx_Udp(sock, (unsigned char *)(pElem->data), (pElem->lData), &sockAddr );
	}
	return;
}

static 	void 	_SLog_RecAnchor(_t_log_ctrl * pCtrl, _t_log_anchor * pAnchor)
{
	int 				i;
	_t_log_elem 	* 	pElem;
	
	
	if(pCtrl && pAnchor){
		/* Now Let's Get the Real Rec Process Func Ptr */
		for(i=0, pElem = (_t_log_elem*)(pAnchor->queue.next); 
			i < pAnchor->queue.count; 
			i++, pElem = (_t_log_elem*)(pElem->node.next)){
			switch(pElem->type){
				case _S_LOG_T_ASCII:
					if( (pCtrl->bkEnd & _S_LOG_BKEND_STD) ||
						(pCtrl->bkEnd & _S_LOG_BKEND_FILE)){
						_SLog_RecFileAscii(pCtrl, pElem);
					}
					break;
		
				case _S_LOG_T_BINARY:
					if( (pCtrl->bkEnd & _S_LOG_BKEND_STD) ||
						(pCtrl->bkEnd & _S_LOG_BKEND_FILE)){
						_SLog_RecFileBinary(pCtrl, pElem);
					}
					break;
					
				case _S_LOG_T_MFILE: /* Index + Data File */
					if( (pCtrl->bkEnd & _S_LOG_BKEND_STD) ||
						(pCtrl->bkEnd & _S_LOG_BKEND_FILE)){
						_SLog_RecFileMon(pCtrl, pElem);
					}
					break;
		
				case _S_LOG_T_MNET: /* Index + Data File */
					if( (pCtrl->bkEnd & _S_LOG_BKEND_STD) ||
						(pCtrl->bkEnd & _S_LOG_BKEND_FILE)){
						_SLog_RecFileMon(pCtrl, pElem);
					}
					if(pCtrl->bkEnd & _S_LOG_BKEND_NET){
						_SLog_RecNet(pCtrl, pElem);
					}
					break;
			
				default:
					break;
			}
		}
		
		/* Free the whole Anchor's Queue  & Free the Anchor */
		_S_LOG_ANCHOR_FREE(pCtrl, pAnchor);
	}
	
	return;
}


/* =====================================================================
** Log Record Task:
**
*/

#define _S_LOG_ANCHORQ_FREE(pCtrl, pQue, pAnchor) \
	do{\
		SYS_ENTER_CS(&(pCtrl->lock));\
		while((pAnchor = (_t_log_anchor *)BLST_GET(pQue))){\
			MPool_FreeNi(&(pCtrl->mPool), &(pAnchor->queue));\
			BLST_ADD2H(&(pCtrl->aFreeQ),  &(pAnchor->node));\
		}\
		SYS_LEAVE_CS(&(pCtrl->lock));\
	}while(0)


static 	void * 	_SLog_Task(_t_log_task * pTask)
{
	int 				i, ret;
	_t_blist 	    	recQue;
	_t_log_anchor  		* pAnchor;	
	_t_log_ctrl 	  	* pCtrl;

	void (*pRecProc)(_t_log_ctrl*, _t_log_anchor*);

	STask_Attr(&(pTask->attr));
	STask_SetName("Ak_Log");

	while(1){
		/* We wait here for Wakeup */
		SYS_SEM_B_TAKE(&(pTask->wake), _WAIT_FOREVER);

		for(i=0, pCtrl=pTask->ctrl; i<_S_LOG_MAX_CTRL; i++, pCtrl++){
			BLIST_INIT(&recQue);
			pRecProc = NULL;
			
			/* Check the Ascii/Binary Queue Anchor */
			if(pCtrl->aActvQ.count > 0){
				SYS_ENTER_CS(&(pCtrl->lock));
				BLST_CAT(&recQue, &(pCtrl->aActvQ));
				SYS_LEAVE_CS(&(pCtrl->lock));
			}
			
			/* Now Let's Get the Real Rec Process Func Ptr */
			ret = pCtrl->bkEnd & (_S_LOG_BKEND_STD | _S_LOG_BKEND_FILE | _S_LOG_BKEND_NET);
			if(ret){
				pRecProc = (void (*)(_t_log_ctrl*, _t_log_anchor*))(pCtrl->funcRec);
			}
			
			/* Now Let's Record*/
			if(recQue.count > 0){
				if(pRecProc){
					while((pAnchor = (_t_log_anchor *)BLST_GET(&recQue))){
						pRecProc(pCtrl, pAnchor);
					};
				}
				else{
					/* Free the whole Anchor's Queue */
					_S_LOG_ANCHORQ_FREE(pCtrl, &recQue, pAnchor);
				}
			}

		}
	}
	
	return NULL;
}


/* =====================================================================
** Log Elem Pool & Global Vars Init, Spawn the Record Task.
**
*/
#define _S_LOG_TO 	2

#define _S_LOG_ANCHOR_A_ACTIVE(pCtrl, pAnchor) \
	do{\
		SYS_ENTER_CS(&(pCtrl->lock));\
		\
		/* Get a new Anchor */\
		SYS_LEAVE_CS(&(pCtrl->lock));\
	}while(0)
	

static 	int 	_SLog_Trigger(_t_log_ctrl * pCtrl, _t_log_elem * pElem)
{
	int  ret, bWake;
	_t_log_anchor 	* pAnchor;
	_t_log_task 	* pTask;
	ret 	= _E_FAIL;
	bWake	= 0;
	if(pCtrl && pElem){
		pTask = pCtrl->pTask;

		if(pTask){
			SYS_ENTER_CS(&(pCtrl->lock));
			
			if(pCtrl->pAnchor == NULL){
				pCtrl->pAnchor = (_t_log_anchor *)BLST_GET(&(pCtrl->aFreeQ));
			}
			/* Check If Anchor is Valid */
			pAnchor = pCtrl->pAnchor;
			if(pAnchor){
				BLST_ADD2T(&(pAnchor->queue), &(pElem->node));

				/* Check If Trigger Rec */
				if(pAnchor->queue.count > pCtrl->eThrs){
					BLST_ADD2T(&(pCtrl->aActvQ), &(pAnchor->node));
					pCtrl->pAnchor = (_t_log_anchor *)BLST_GET(&(pCtrl->aFreeQ));
					bWake = 1;
				}
				ret = _E_SUCC;
			}
			
			SYS_LEAVE_CS(&(pCtrl->lock));
			if(bWake == 1){
				SYS_SEM_B_GIVE(&(pTask->wake));
			}
		}
	}
	return ret;
}

static 	int 	_SLog_RecTrig(_t_log_task * pTask, _t_log_ctrl * pCtrl, int eThrs)
{
	int  ret, bWake;
	_t_log_anchor * pAnchor;

	ret 	= _E_FAIL;
	bWake	= 0;
	if(pCtrl){
		SYS_ENTER_CS(&(pCtrl->lock));
		
			pAnchor = pCtrl->pAnchor;
			if(	(pAnchor)&& (pAnchor->queue.count > eThrs)){
				/* Let's trigger a Record Operation */
				BLST_ADD2T(&(pCtrl->aActvQ), &(pAnchor->node));
				pCtrl->pAnchor = (_t_log_anchor *)BLST_GET(&(pCtrl->aFreeQ));\
				bWake 	= 1;
				ret 	= _E_SUCC;
			}
			
		SYS_LEAVE_CS(&(pCtrl->lock));
		if(bWake == 1){
			SYS_SEM_B_GIVE(&(pTask->wake));
		}
	}
	
	return ret;
}


#define _SLOG_TASK_TIMER 		0X10
static 	int 	_SLog_RecTimer(_t_log_task * pTask)
{	
	int i;
	if(pTask){
		pTask->timer = (pTask->timer + 1) % _SLOG_TASK_TIMER;
		if(pTask){
			for(i=0; i<_S_LOG_MAX_CTRL; i++){
				_SLog_RecTrig(pTask, (pTask->ctrl + i), 0);
			}
		}
	}
	return 0;
}

#define _S_LOG_PARAM_SET(pCtrl, vESize, vETotal, vEThrs, vFunc) \
	do{\
		(pCtrl)->eSize = vESize;\
		(pCtrl)->eTotal= vETotal;\
		(pCtrl)->eThrs = vEThrs;\
		(pCtrl)->funcRec= vFunc;\
	}while(0)


#define _SLOG_TASK_STACK 		0X100000
#define _SLOG_TASK_PRI 			90

int 	SLog_Exec(_t_log_task * pTask)
{
	int 	ret;
	_t_cbentry 	  	cbEntry;

	ret = _E_FAIL;
	if(pTask){
		/* Register the Trigger */
		pTask->timer = 0;
		_CBENTRY_INIT(&cbEntry, _SLog_RecTimer, pTask, 0);
		STrigger_Add(&cbEntry);
		STASK_CRATE(pTask->task, 
				_SLOG_TASK_STACK,
				_SLOG_TASK_PRI,
				_SLog_Task, 
				pTask);
		ret = _E_SUCC;
	}
	return ret;
}

int 	SLog_Init(_t_log_task * pTask)
{
	int 			ret, i, j, size, mLimit;
	_t_log_anchor 	* pAnchor;
	_t_log_ctrl 	* pCtrl;

	ret = _E_FAIL;
	if(pTask){
		/* Init the Global Variables, Queues, Structures */
		SYS_SEM_B_INIT(&(pTask->wake));
		
		for(i=0, pCtrl=pTask->ctrl; i<_S_LOG_MAX_CTRL; i++, pCtrl++){
			SYS_INIT_CS(&(pCtrl->lock));			
			BLIST_INIT(&(pCtrl->aFreeQ));			BLIST_INIT(&(pCtrl->aActvQ));	
			pCtrl->pTask 		= pTask;
			pCtrl->pAnchor 		= NULL;
			/* BackEnd */
			pCtrl->filePath[0]	= '\0';
			pCtrl->pFileI 		= NULL;
			pCtrl->pFileA 		= NULL;
			pCtrl->pFileB 		= NULL;
			pCtrl->pFileM 		= NULL;
			pCtrl->sock 		= S_SOCKET_INVALID;
			pCtrl->bNet 		= 0;
			pCtrl->iFile 		= 0;
			pCtrl->iCount 		= 0;
			pCtrl->iOffset 		= 0;
			_IPPORT_INIT(&(pCtrl->ipPort));
			
			_S_LOG_PARAM_SET(pCtrl, 
					_S_LOG_ELEM_MAXSZ, 
					_S_LOG_ELEM_MAXCNT,
					_S_LOG_ELEM_THRS,
					_SLog_RecAnchor);

			/* Anchor Init */
			for(j=0, pAnchor=pCtrl->anchorAU; j<_S_LOG_MAX_ANCHOR; j++, pAnchor++){
				pAnchor->index = i;
				BLIST_INIT(&(pAnchor->queue)); 
				BNODE_INIT(&(pAnchor->node));
				BLST_ADD2T(&(pCtrl->aFreeQ),&(pAnchor->node));
			}
			
			/* Memory of Ascii Log, We make sure the Ascii Log Buffer could be Allocated! 
			** If Binary Log Buffer is not allocated Succ, It's OK, we just disable the Binary Logging Service.
			*/
			size 	= sizeof(_t_log_elem) + pCtrl->eSize;
			mLimit 	= size * pCtrl->eTotal;
			MHeap_InitEx(&(pCtrl->mHeap), mLimit);
			MPool_Init(&(pCtrl->mPool), &(pCtrl->mHeap),	
						mLimit, sizeof(_t_sysMi), 
						1,	 1, MPOOL_T_SIMP);
			/* Init the Slot */
			MPOOL_SET_SLOT(&(pCtrl->mPool), &(pCtrl->mSlot));
			MSlot_Init(&(pCtrl->mSlot), &(pCtrl->mPool), 0, (unsigned int)size);
				
		}

		ret = _E_SUCC;
	}
		
	return ret;
}


/* =====================================================================
** Log Interface Function:
**
*/
#define _S_LOG_ELEM_ALLOC(pCtrl, pElem, vType) \
	do{\
		pElem = (_t_log_elem *)MPool_AllocSi(&(pCtrl->mPool));\
		if(pElem){\
			(pElem)->type = (unsigned char)(vType);\
		}\
	}while(0)

#define _S_LOG_ELEM_FREE(pCtrl, pElem) \
	do{\
		MPool_FreeSi(&(pCtrl->mPool), pElem);\
	}while(0)


int 		SLogging(_t_log_ctrl 	* pCtrl,	int type,
						const char  * sFunc, 	int nLine,
						char 		* pDesc, 	int descLen,
						char 		* pData, 	int dataLen)
{
	_t_log_elem *	pElem;
	struct tm	   *tm;
	struct timeval	tv;
	int            	ret;
	
	ret = _E_FAIL;	
	/* We use the pKey->tbl[0].b8[0] to Get the PriMod */
	if( pCtrl && (dataLen > 0) && (descLen < (_S_LOG_MAX_DESC - 2))){
		_S_LOG_ELEM_ALLOC(pCtrl, pElem, type);

		if(pElem){
			/* Timing */
			gettimeofday(&tv, NULL); 		tm = localtime(&(tv.tv_sec));
			SVFS_TIMING(&(pElem->idx), tm, (tv.tv_usec/1000), (tv.tv_usec%1000));
			pElem->idx.i_idx 	= 0;
			pElem->idx.i_off 	= 0;
			pElem->idx.i_len 	= dataLen;
			pElem->idx.i_reserv = 0;

			/* SFunc & SLine */
			if(sFunc){
				SYS_SNPRINTF(pElem->sFunc, (_S_LOG_MAX_SFUNC - 1), "%s", sFunc);
			}else{
				pElem->sFunc[0] = '\0';
			}
			pElem->sLine = nLine;

			/* User Summit */
			if(descLen >= _S_LOG_MAX_DESC)
				descLen = _S_LOG_MAX_DESC;
			pElem->desc[0] = 0;
			pElem->lDesc = descLen;
			if(descLen > 0){
				SYS_MEMCPY((pElem->desc), pDesc, descLen);
			}

			/* User Data */
			if(dataLen >= _S_LOG_ELEM_MAXSZ)
				dataLen = _S_LOG_ELEM_MAXSZ;
			pElem->data[0] = 0;
			pElem->lData = dataLen;
			SYS_MEMCPY(pElem->data, pData, dataLen);

			/* Checking if could trigger a Log */
			ret = _SLog_Trigger(pCtrl, pElem);
			if(ret == _E_FAIL){
				_S_LOG_ELEM_FREE(pCtrl, pElem);
			}
		}
	}		

	return ret;
}


int 	SLog_SetBkEnd(_t_log_ctrl* pCtrl,  int bkEnd, const char * filePath, unsigned int ip, unsigned short port)
{
	int  			ret;

	ret = _E_FAIL;	
	if(pCtrl){
		if(bkEnd & _S_LOG_BKEND_STD){
				pCtrl->bkEnd  |= _S_LOG_BKEND_STD;
				pCtrl->pFileA = stdout;
				pCtrl->pFileB = stdout;
				pCtrl->pFileM = NULL;
		}
		if(bkEnd & _S_LOG_BKEND_FILE){
			_SLog_BkFileI(pCtrl, filePath);
			if(!(pCtrl->pFileI)){
				pCtrl->bkEnd |= _S_LOG_BKEND_STD;
				pCtrl->pFileA = stdout;
				pCtrl->pFileB = stdout;
				pCtrl->pFileM = NULL;
			}
			else{
				pCtrl->bkEnd |= _S_LOG_BKEND_FILE;
			}
		}
		if(bkEnd & _S_LOG_BKEND_DB){
			#if 0
			pCtrl->bkEnd |= _S_LOG_BKEND_DB;
			#endif
		}
		if(bkEnd & _S_LOG_BKEND_NET){
			_IPPORT_GEN(&(pCtrl->ipPort), ip, port);
			if(pCtrl->sock == S_SOCKET_INVALID){
				pCtrl->sock = SockCreate_Udp(_F_NO, _S_LOG_SVR_PORT);
				S_SOCK_SET_NONBLOCK(pCtrl->sock, ret);
				S_SOCK_SET_NOCHKSUM(pCtrl->sock, ret);
				S_SOCK_SET_LOWDELAY(pCtrl->sock, ret);
			}
			pCtrl->bkEnd |= _S_LOG_BKEND_NET;
		}

		ret = _E_SUCC;
	}
	
	return ret;
}



/* =====================================================================
** Log Monitor Function:
**
*/
int 		SMon_Init(_t_log_mon * pMon, const char * filePath)
{
	int 				fd, ret;
	struct stat 		fStat;
	char				fPath[S_APP_MAX_PATH];
	
	ret = -1;
	if(pMon){
		if((filePath) && (SYS_STRLEN(filePath) < (S_APP_MAX_PATH - 10))){
			SYS_SNPRINTF(pMon->filePath, (S_APP_MAX_PATH-1), "%s", filePath);
		}else{
			SYS_SNPRINTF(pMon->filePath, (S_APP_MAX_PATH-1), "/tmp/");
		}
		pMon->pFileI= NULL;
		pMon->pFileM= NULL;
		/* First Check if Has the Index File :
		** a+
		** Open for reading and appending (writing at end of file).
		** The file is created if it does not exist. 
		** The initial file position for reading is at the beginning of the file, 
		** but output is always appended to the end of the file.
		*/
		SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.idx", filePath);
		pMon->iCount = 0;
		pMon->iFile  = 0;
		pMon->iOffset= 0;
		/* File Stat */
		fd = open(fPath, O_RDWR);
		ret = fstat(fd, &fStat);
		if(ret == 0){
			pMon->iCount = fStat.st_size / sizeof(_t_vfs_ti);
		}
		close(fd);
		
		SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileI Total: (%d)\n", pMon->iCount);
		pMon->pFileI= fopen(fPath, "r");
	}

	return ret;
}


static 	int 		_SMon_BkFileM(_t_log_mon * pMon, int fIdx)
{
	int 				ret;
	char				fPath[S_APP_MAX_PATH];
	
	ret = -1;
	if(pMon && (pMon->pFileI) && (fIdx >= 0)){
		ret = pMon->iCount / _S_LOG_MAX_FITEM;
		if(fIdx <= ret){
			if(	(pMon->iFile != fIdx) || (!pMon->pFileM)){
				if(pMon->pFileM){
					fclose(pMon->pFileM);
					pMon->pFileM = NULL;
				}
				
				SYS_SNPRINTF(fPath, (S_APP_MAX_PATH-1), "%s/log.m.%04d", pMon->filePath, fIdx);
				pMon->pFileM= fopen(fPath, "r");
				SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileM (%d) Close - (%d) Open\n", 
					pMon->iFile, fIdx);

				/* Set the iOffset */
				pMon->iFile   = fIdx;
				pMon->iOffset = 0;
			}
			
			ret = 0;
		}
	}

	return ret;
}


static 	int 		_SMon_BkFileM_Off(_t_log_mon * pMon, int eIdx, _t_vfs_ti * pIdx)
{
	int 				ret;
	
	ret = -1;
	if(	pMon &&  (eIdx >= 0) && (eIdx <= pMon->iCount) && (pMon->pFileI)){
		ret = eIdx / _S_LOG_MAX_FITEM;
		_SMon_BkFileM(pMon, ret);
		ret = eIdx % _S_LOG_MAX_FITEM;
		
		/* Indexing */
		if(eIdx > 0){
			fseek(pMon->pFileI, (eIdx -1)*sizeof(_t_vfs_ti), SEEK_SET);
		}
		
		fread(pIdx, sizeof(_t_vfs_ti), 1, pMon->pFileI);
		SYS_TRACE(_gTraceLvl_Log, TRACELVL_DEBUG, "FileM (%d) eNo(%d) [%d - %d]\n", 
			pMon->iFile, eIdx, 
			pIdx->i_off, pIdx->i_len);
		ret = 0;
	}

	return ret;
}


int 		SMon_Show(_t_log_mon * pMon, int eIdx, unsigned char * pBuf, unsigned int lBuf)
{
	int 			ret;
	_t_vfs_ti 		lIdx;
	unsigned char 	buf[_S_LOG_ELEM_MAXSZ];
	
	ret = _SMon_BkFileM_Off(pMon, eIdx, &lIdx);
	if(ret == 0){
		/* Seek */
		if(pMon->pFileM){
			printf("<Y/M/D %4d-%02d-%02d>(H/M/S %02d:%02d:%02d)[%03d:%03d] File[%04d](No:%d Off:%d Len:%d)\n", 
					lIdx.t_year + 1900,	lIdx.t_mon  + 1,	lIdx.t_mday,
					lIdx.t_hour,		lIdx.t_min,			lIdx.t_sec,
					lIdx.t_msec,		lIdx.t_usec,
					eIdx / _S_LOG_MAX_FITEM,
					eIdx % _S_LOG_MAX_FITEM,
					lIdx.i_off,
					lIdx.i_len);
					
			fseek(pMon->pFileM, lIdx.i_off, SEEK_SET);
			fread(buf, lIdx.i_len, 1, pMon->pFileM);
			STrace_HexDump(buf, lIdx.i_len);
			if(pBuf && (lBuf >= lIdx.i_len)){
				SYS_MEMCPY(pBuf, buf, lIdx.i_len);
				return lIdx.i_len;
			}
		}
	}

	return 0;
}


int 		SMon_Fini(_t_log_mon * pMon)
{
	if(pMon){
		/* Close File */
		if(pMon->pFileI){
			fclose(pMon->pFileI);
			pMon->pFileI = NULL;
		}
		if(pMon->pFileM){
			fclose(pMon->pFileM);
			pMon->pFileM = NULL;
		}
		/* Clear Var */
		pMon->iCount = 0;
		pMon->iFile  = 0;
		pMon->iOffset= 0;
		return 0;
	}

	return -1;
}

